// SPDX-FileCopyrightText: Adam Evyčędo
//
// SPDX-License-Identifier: AGPL-3.0-or-later

package traffic

import (
	"apiote.xyz/p/szczanieckiej/config"
	"apiote.xyz/p/szczanieckiej/file"

	"fmt"
	"net/http"
	"path/filepath"
	"sort"
	"strings"
	"time"

	"golang.org/x/text/transform"
)

type Feed interface {
	fmt.Stringer
	ConvertVehicles() ([]Vehicle, error)
	GetVersions(time.Time, *time.Location) ([]Version, error)
	RealtimeFeeds() map[RealtimeFeedType]string
	Transformer() transform.Transformer
	Name() string
	Flags() FeedFlags
	FeedPrepareZip(string) error
	QRInfo() (string, QRLocation, string)

	getTimezone() *time.Location
}

type HeadsignSource uint

const (
	HeadsignTripHeadsing HeadsignSource = iota
	HeadsignTripLastStop
)

type FeedFlags struct {
	Headsign     HeadsignSource
	StopIdFormat string
	StopName     string
	LineName     string
}

func FeedPath(cfg config.Config, feed Feed) string {
	return filepath.Join(cfg.FeedsPath, feed.String())
}

func RegisterFeeds() map[string]Feed {
	return map[string]Feed{
		"poznan_ztm": PoznanZtm{
			client: http.Client{
				Timeout: 30 * time.Second,
			},
		},
		// "krakow_ztp":         KrakowZtp{},
		"gzm_ztm":            GzmZtm{},
		"berlin_vbb":         BerlinVbb{},
		"brussels_stib_mivb": BrusselsStibMivb{},
		"calgary_transit":    CalgaryTransit{},
		"rockhill_myride":    RockHillMyRide{},
	}
}

func MakeVersion(s string) (Version, error) {
	version := Version{}
	versionDates := strings.Split(s, "_")
	if len(versionDates) != 2 {
		return version, fmt.Errorf("invalid version string %s, not /.*_.*/", s)
	}
	versionDates[0] += "000000"
	versionDates[1] += "235900"
	validFrom, err := time.Parse(ValidityFormatExtended, versionDates[0])
	if err != nil {
		return version, fmt.Errorf("invalid first part in %s: %w", s, err)
	}
	validTill, err := time.Parse(ValidityFormatExtended, versionDates[1])
	if err != nil {
		return version, fmt.Errorf("invalid second part in %s: %w", s, err)
	}
	version.ValidFrom = validFrom
	version.ValidTill = validTill
	return version, nil
}

func MakeVersionTimezone(s string, timezone *time.Location) (Version, error) {
	version := Version{}
	versionDates := strings.Split(s, "_")
	if len(versionDates) != 2 {
		return version, fmt.Errorf("invalid version string %s, not /.*_.*/", s)
	}
	versionDates[0] += "000000"
	versionDates[1] += "235900"
	validFrom, err := time.ParseInLocation(ValidityFormatExtended, versionDates[0], timezone)
	if err != nil {
		return version, fmt.Errorf("invalid first part in %s: %w", s, err)
	}
	validTill, err := time.ParseInLocation(ValidityFormatExtended, versionDates[1], timezone)
	if err != nil {
		return version, fmt.Errorf("invalid second part in %s: %w", s, err)
	}
	version.ValidFrom = validFrom
	version.ValidTill = validTill
	return version, nil
}

func ListVersions(cfg config.Config, f Feed) ([]string, error) {
	return file.ListVersions(FeedPath(cfg, f))
}

func ListVersionsTimezone(cfg config.Config, f Feed, timezone *time.Location) ([]Version, error) {
	versions := []Version{}
	validities, err := ListVersions(cfg, f)
	if err != nil {
		return versions, fmt.Errorf("while listing versions: %w", err)
	}

	for _, validity := range validities {
		version, err := MakeVersionTimezone(validity, timezone)
		if err != nil {
			return versions, fmt.Errorf("while making version of %s: %w", validity, err)
		}
		versions = append(versions, version)
	}
	return versions, nil
}

func FindValidVersions(versions []Version, now time.Time) []Version {
	result := []Version{}
	if len(versions) == 0 {
		return versions
	}
	if len(versions) == 1 {
		if versions[0].ValidTill.IsZero() || (now.Before(versions[0].ValidTill) && now.After(versions[0].ValidFrom)) {
			return versions
		} else {
			return []Version{}
		}
	}

	sort.Slice(versions, func(i, j int) bool {
		return versions[i].ValidFrom.After(versions[j].ValidFrom)
	})

	for _, version := range versions {
		if version.ValidTill.IsZero() || now.Before(version.ValidFrom) {
			result = append([]Version{version}, result...)
			continue
		}
		if now.After(version.ValidFrom) { // TODO and before validTill??
			result = append([]Version{version}, result...)
			break
		}
	}

	return result
}
